#include "bsp_lcd.h"
#include "bsp_board.h"
#include <at32f403a_407.h>

static volatile uint8_t dma_trans_done_flag = 1;

void DMA1_Channel5_IRQHandler(void)
{
    if(dma_flag_get(DMA1_FDT5_FLAG) != RESET)
    {
        dma_trans_done_flag = 1;
        dma_reset(DMA1_CHANNEL5); //复位DMA通道
    }
}
static void lcd_bus_init()
{
    //LCD_SCL->PB13(LCD_SPI_PR_SCK) LCD_DC->PB14 LCD_SDA->PB15(LCD_SPI_PR_MOSI) LCD_CS->PB4 LCD_BL->PA8
	crm_periph_clock_enable(CRM_IOMUX_PERIPH_CLOCK, TRUE); 					//使能复用时钟
    crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE); 					//使能GPIOB外设时钟
	crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE); 					//使能GPIOB外设时钟
	
	gpio_pin_remap_config(SWJTAG_MUX_001, TRUE);
	
    gpio_init_type gpio_initstructure;
    gpio_default_para_init(&gpio_initstructure);
    
    gpio_initstructure.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
    gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
    gpio_initstructure.gpio_mode           = GPIO_MODE_MUX;
	//PB13=LCD_SPI_PR_CLK  PB15=LCD_SPI_PR_MOSI
    gpio_initstructure.gpio_pins           = GPIO_PINS_13 | GPIO_PINS_15; 	
    gpio_init(GPIOB, &gpio_initstructure);
    //PB14=LCD_DC  PB4=LCD_SPI_PR_CS
    gpio_initstructure.gpio_mode           = GPIO_MODE_OUTPUT;
    gpio_initstructure.gpio_pins           = GPIO_PINS_14 | GPIO_PINS_4; 	
    gpio_init(GPIOB, &gpio_initstructure);
	//PA8=LCD_BL
	gpio_initstructure.gpio_pins           = GPIO_PINS_8;
    gpio_init(GPIOA, &gpio_initstructure);
	//PB11=BUZZER_PIN
	gpio_initstructure.gpio_pins           = BUZZER_PIN;
    gpio_init(GPIOB, &gpio_initstructure);
	
//	gpio_pin_remap_config(SWJTAG_MUX_001, TRUE);
    /* SPI外设 */
    crm_periph_clock_enable(LCD_SPI_CLOCK, TRUE); 							//使能SPI外设时钟

    spi_init_type spi_init_struct;
    spi_default_para_init(&spi_init_struct);
    
    spi_init_struct.transmission_mode = SPI_TRANSMIT_HALF_DUPLEX_TX; 		//仅发送
    spi_init_struct.master_slave_mode = SPI_MODE_MASTER;
    spi_init_struct.mclk_freq_division = SPI_MCLK_DIV_2; 					//120/2=60Mhz
    spi_init_struct.first_bit_transmission = SPI_FIRST_BIT_MSB;				//数据传输高位先行	
    spi_init_struct.frame_bit_num = SPI_FRAME_8BIT;							//设置SPI数据大小：8位帧结构
    spi_init_struct.clock_polarity = SPI_CLOCK_POLARITY_HIGH;				//串行同步时钟空闲时SCLK位高电平
    spi_init_struct.clock_phase = SPI_CLOCK_PHASE_2EDGE;					//串行同步时钟空第二个时钟沿捕获
    spi_init_struct.cs_mode_selection = SPI_CS_SOFTWARE_MODE;
    spi_init(LCD_SPI_PR, &spi_init_struct);
    
    spi_i2s_dma_transmitter_enable(LCD_SPI_PR, TRUE); 						//使能SPI发送DMA请求
    spi_enable(LCD_SPI_PR, TRUE);
//    dma_flexible_config(DMA1, FLEX_CHANNEL2, DMA_FLEXIBLE_SPI2_TX);
    /* DMA外设 */
    crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
    nvic_irq_enable(DMA1_Channel5_IRQn, 1, 0); 								//使能DMA中断请求
//    nvic_irq_enable(DMA1_Channel2_IRQn, 3 , 0);
//    dma_reset(DMA1_CHANNEL2);
	LCD_BL_On();
	LCD_CS_On(); //CS=1
    LCD_DC_On(); //D/C=1, 数据
	BUZZER_Off();
}
static void lcd_write_byte(uint8_t value_t){
	LCD_CS_Off(); //CS=0 
    spi_frame_bit_num_set(LCD_SPI_PR, SPI_FRAME_8BIT);
    while(spi_i2s_flag_get(LCD_SPI_PR, SPI_I2S_BF_FLAG) == SET); 			//等待传输完成
    spi_i2s_data_transmit(LCD_SPI_PR, value_t);
    while(spi_i2s_flag_get(LCD_SPI_PR, SPI_I2S_BF_FLAG) == SET); 			//等待传输完成
    LCD_CS_On(); //CS=1
}
static void lcd_send_cmd(uint8_t cmd)
{
    LCD_DC_Off(); //D/C=0, 指令
    lcd_write_byte(cmd);
    LCD_DC_On(); //D/C=1, 数据
}

static void lcd_send_data(const uint8_t *data, uint8_t len)
{
    for(uint8_t i = 0; i < len; i ++) {
		lcd_write_byte(data[i]);
    }
}
static void lcd_send_color(const uint8_t *data, uint32_t len)
{
//    spi_frame_bit_num_set(LCD_SPI_PR, SPI_FRAME_16BIT);
    dma_init_type dma_init_struct;
    
    dma_init_struct.buffer_size = len*2;
    dma_init_struct.direction = DMA_DIR_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_base_addr = (uint32_t)data;
    dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
    dma_init_struct.memory_inc_enable = TRUE;
    dma_init_struct.peripheral_base_addr = (uint32_t)&(LCD_SPI_PR->dt);
    dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
    dma_init_struct.peripheral_inc_enable = FALSE;
    dma_init_struct.priority = DMA_PRIORITY_MEDIUM;
    dma_init_struct.loop_mode_enable = FALSE;
    
    dma_init(DMA1_CHANNEL5, &dma_init_struct);
    dma_interrupt_enable(DMA1_CHANNEL5, DMA_FDT_INT, TRUE); 				//开启DMA传输完成中断
	
    LCD_CS_Off(); 															//CS=0
    dma_channel_enable(DMA1_CHANNEL5, TRUE); 								//启动传输
}

/* 黑色320*240 IPS */
static void lcd_reg_init_st7789v()
{
//    /* 退出睡眠模式 */
//    lcd_send_cmd(0x11);
//	delay_ms(150);
//    /* 显存访问控制 */
//    lcd_send_cmd(0x36);
////	lcd_send_data((uint8_t[]){0x70}, 1); //MX=MV=1, MY=ML=MH=0, RGB=0 横屏, 芯片在右
//	lcd_send_data((uint8_t[]){0xA0}, 1); //MY=MV=1, MX=ML=MH=0, RGB=0 横屏，芯片在左
////    lcd_send_data((uint8_t[]){0xC0}, 1); //MX=MV=MY=ML=MH=0, RGB=0 竖屏，芯片在下
////    lcd_send_data((uint8_t[]){0x00}, 1); //MX=MV=MY=ML=MH=0, RGB=0 竖屏，芯片在下
//    /* 像素格式 */
//    lcd_send_cmd(0x3A);
//    lcd_send_data((uint8_t[]){0x05}, 1); //MCU mode, 16bit/pixel
//    /* Porch设置 */
//    lcd_send_cmd(0xB2);
//    lcd_send_data((uint8_t[]){0x0C, 0x0C, 0x00, 0x33, 0x33}, 5);
//	delay_ms(150);
//    /* Gate设置 */
//    lcd_send_cmd(0xB7);
//    lcd_send_data((uint8_t[]){0x35}, 1); //Vgh=13.26V, Vgl=-10.43V
//    /* VCOM设置 */
//    lcd_send_cmd(0xBB);
//    lcd_send_data((uint8_t[]){0x35}, 1); //VCOM=0.725V 
//    /* LCN设置 */
//    lcd_send_cmd(0xC0);
//    lcd_send_data((uint8_t[]){0x2C}, 1); //XOR: BGR, MX, MH 
//    /* VDV与VRH写使能 */
//    lcd_send_cmd(0xC2);
//    lcd_send_data((uint8_t[]){0x01}, 1); //CMDEN=1
//    /* VRH设置 */
//    lcd_send_cmd(0xC3);
//    lcd_send_data((uint8_t[]){0x13}, 1); //Vrh=4.45+
//    /* VDV设置 */
//    lcd_send_cmd(0xC4);
//    lcd_send_data((uint8_t[]){0x20}, 1); //Vdv=0
//    /* 刷新率设置 */
//    lcd_send_cmd(0xC6);
//    lcd_send_data((uint8_t[]){0x0F}, 1); //60Hz, no column inversion
//    /* 电源控制1 */
//    lcd_send_cmd(0xD0);
//    lcd_send_data((uint8_t[]){0xA4, 0xA1}, 2); //AVDD=6.8V, AVCL=-4.8V, VDDS=2.3V
//	//
//    lcd_send_cmd(0xD6);
//    lcd_send_data((uint8_t[]){0xA1}, 1); //
//    /* 正电压伽马控制 */
//    lcd_send_cmd(0xE0);
//    lcd_send_data((uint8_t[]){0xF0, 0x00, 0x04, 0x04, 0x04, 0x05, 0x29, 
//							  0x33, 0x3E, 0x38, 0x12, 0x12, 0x28, 0x30}, 14);
//    /* 负电压伽马控制 */
//    lcd_send_cmd(0xE1);
//    lcd_send_data((uint8_t[]){0xF0, 0x07, 0x0A, 0x0D, 0x0B, 0x07, 0x28, 
//							  0x33, 0x3E, 0x36, 0x14, 0x14, 0x29, 0x32}, 14);
//	/* IPS屏幕需要设置屏幕反显才能显示正确的颜色 */
//    lcd_send_cmd(0x21); //开启反显
//1.14
 /* 退出睡眠模式 */
    lcd_send_cmd(0x11);
    /* IPS屏幕需要设置屏幕反显才能显示正确的颜色 */
    lcd_send_cmd(0x21); //开启反显
    //lcd_send_cmd(0x20); //关闭反显
    /* 显存访问控制 */
    lcd_send_cmd(0x36);
//    lcd_send_data((uint8_t[]){0x60}, 1); //MX=MV=1, MY=ML=MH=0, RGB=0 横屏, 芯片在右
    lcd_send_data((uint8_t[]){0xA0}, 1); //MY=MV=1, MX=ML=MH=0, RGB=0 横屏，芯片在左
//    lcd_send_data((uint8_t[]){0x00}, 1); //MX=MV=MY=ML=MH=0, RGB=0 竖屏，芯片在下
    /* 像素格式 */
    lcd_send_cmd(0x3A);
    lcd_send_data((uint8_t[]){0x05}, 1); //MCU mode, 16bit/pixel
    /* Porch设置 */
    lcd_send_cmd(0xB2);
    lcd_send_data((uint8_t[]){0x0C, 0x0C, 0x00, 0x33, 0x33}, 5);
    /* Gate设置 */
    lcd_send_cmd(0xB7);
    lcd_send_data((uint8_t[]){0x35}, 1); //Vgh=13.26V, Vgl=-10.43V
    /* VCOM设置 */
    lcd_send_cmd(0xBB);
    lcd_send_data((uint8_t[]){0x19}, 1); //VCOM=0.725V 
    /* LCN设置 */
    lcd_send_cmd(0xC0);
    lcd_send_data((uint8_t[]){0x2C}, 1); //XOR: BGR, MX, MH 
    /* VDV与VRH写使能 */
    lcd_send_cmd(0xC2);
    lcd_send_data((uint8_t[]){0x01, 0xFF}, 2); //CMDEN=1
    /* VRH设置 */
    lcd_send_cmd(0xC3);
    lcd_send_data((uint8_t[]){0x12}, 1); //Vrh=4.45+
    /* VDV设置 */
    lcd_send_cmd(0xC4);
    lcd_send_data((uint8_t[]){0x20}, 1); //Vdv=0
    /* 刷新率设置 */
    lcd_send_cmd(0xC6);
    lcd_send_data((uint8_t[]){0x0F}, 1); //60Hz, no column inversion
    /* 电源控制1 */
    lcd_send_cmd(0xD0);
    lcd_send_data((uint8_t[]){0xA4, 0xA1}, 2); //AVDD=6.8V, AVCL=-4.8V, VDDS=2.3V0
    /* 正电压伽马控制 */
    lcd_send_cmd(0xE0);
    lcd_send_data((uint8_t[]){0xD0, 0x04, 0x0D, 0x01, 0x13, 0x2B, 0x3F, 
							  0x54, 0x4C, 0x18, 0x0D, 0x0B, 0x1F, 0x23}, 14);
    /* 负电压伽马控制 */
    lcd_send_cmd(0xE1);
    lcd_send_data((uint8_t[]){0xD0, 0x04, 0x0C, 0x11, 0x13, 0x2C, 0x3F, 
							  0x44, 0x51, 0x2F, 0x1F, 0x1F, 0x20, 0x23}, 14);

// /* 退出睡眠模式 */
//    lcd_send_cmd(0x11);
//    /* 显存访问控制 */
//    lcd_send_cmd(0x36);
////    lcd_send_data((uint8_t[]){0x60}, 1); //MX=MV=1, MY=ML=MH=0, RGB=0 横屏, 芯片在右
//    lcd_send_data((uint8_t[]){0xA0}, 1); //MY=MV=1, MX=ML=MH=0, RGB=0 横屏，芯片在左
////    lcd_send_data((uint8_t[]){0x00}, 1); //MX=MV=MY=ML=MH=0, RGB=0 竖屏，芯片在下
//    /* 像素格式 */
//    lcd_send_cmd(0x3A);
//    lcd_send_data((uint8_t[]){0x05}, 1); //MCU mode, 16bit/pixel
//    /* Power contorl B, power control = 0, DC_ENA = 1 */
//	lcd_send_cmd(0xCF);
//	lcd_send_data((uint8_t []){0x00, 0xAA, 0XE0}, 3); 
//	 /* Power on sequence control,
//     * cp1 keeps 1 frame, 1st frame enable
//     * vcl = 0, ddvdh=3, vgh=1, vgl=2
//     * DDVDH_ENH=1
//     */
//	lcd_send_cmd(0xED);
//	lcd_send_data((uint8_t []){0x67, 0x03, 0X12, 0X81}, 4); 
//	/* Driver timing control A,
//     * non-overlap=default +1
//     * EQ=default - 1, CR=default
//     * pre-charge=default - 1
//     */
//	lcd_send_cmd(0xE8);
//	lcd_send_data((uint8_t []){0x8A, 0x01, 0x78}, 3); 
//	/* Power control A, Vcore=1.6V, DDVDH=5.6V */
//	lcd_send_cmd(0xCB);
//	lcd_send_data((uint8_t []){0x39, 0x2C, 0x00, 0x34, 0x02}, 5); 
//	/* Pump ratio control, DDVDH=2xVCl */
//	lcd_send_cmd(0xF7);
//	lcd_send_data((uint8_t []){0x20}, 1); 
//	 /* Driver timing control, all=0 unit */
//	lcd_send_cmd(0xEA);
//	lcd_send_data((uint8_t []){0x00, 0x00}, 2); 
//    /* Power control 1, GVDD=4.75V */
//	lcd_send_cmd(0xC0);
//	lcd_send_data((uint8_t []){0x23}, 1); 
//    /* Power control 2, DDVDH=VCl*2, VGH=VCl*7, VGL=-VCl*3 */
//	lcd_send_cmd(0xC1);
//	lcd_send_data((uint8_t []){0x11}, 1); 
//    /* VCOM control 1, VCOMH=4.025V, VCOML=-0.950V */
//	lcd_send_cmd(0xC5);
//	lcd_send_data((uint8_t []){0x43, 0x4C}, 2); 
//    /* VCOM control 2, VCOMH=VMH-2, VCOML=VML-2 */
//	lcd_send_cmd(0xC7);
//	lcd_send_data((uint8_t []){0xA0}, 1); 
//    /* Frame rate control, f=fosc, 70Hz fps */
//	lcd_send_cmd(0xB1);
//	lcd_send_data( (uint8_t []){0x00, 0x1B}, 2); 
//    /* Enable 3G, disabled */
//	lcd_send_cmd(0xF2);
//	lcd_send_data((uint8_t []){0x00},1); 
//    /* Gamma set, curve 1 */
//	lcd_send_cmd(0x26);
//	lcd_send_data((uint8_t []){0x01}, 1); 
//    /* Positive gamma correction */
//	lcd_send_cmd(0xE0);
//	lcd_send_data((uint8_t []){0x1F, 0x36, 0x36, 0x3A, 0x0C, 0x05, 0x4F, 0X87, 0x3C, 0x08, 0x11, 0x35, 0x19, 0x13, 0x00}, 15); 
//    /* Negative gamma correction */
//	lcd_send_cmd(0xE1);
//	lcd_send_data((uint8_t []){0x00, 0x09, 0x09, 0x05, 0x13, 0x0A, 0x30, 0x78, 0x43, 0x07, 0x0E, 0x0A, 0x26, 0x2C, 0x1F}, 15); 
//    /* Entry mode set, Low vol detect disabled, normal display */
//	lcd_send_cmd(0xB7);
//	lcd_send_data((uint8_t []){0x07}, 1); 
//    /* Display function control */
//	lcd_send_cmd(0xB6);
//	lcd_send_data((uint8_t []){0x08, 0x82, 0x27}, 3); 
//	/* IPS屏幕需要设置屏幕反显才能显示正确的颜色 */
//    lcd_send_cmd(0x21); //开启反显
}

void bsp_lcd_draw_rect(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, const uint8_t *pix_data)
{
    uint8_t tx_data[4];
//    x0=x0+34;
//	x1=x1+34;
//	y0=y0+34;
//	y1=y1+34;
	
    /* 设置Column地址 */
    tx_data[0] = x0>>8; //起始地址高8位
    tx_data[1] = x0&0xFF; //起始地址高8位
    tx_data[2] = x1>>8; //结束地址高8位
    tx_data[3] = x1&0xFF; //结束地址高8位
    lcd_send_cmd(0x2A);
    lcd_send_data(tx_data, 4);

    /* 设置Page地址 */
    tx_data[0] = y0>>8;
    tx_data[1] = y0&0xFF;
    tx_data[2] = y1>>8;
    tx_data[3] = y1&0xFF;
    lcd_send_cmd(0x2B);
    lcd_send_data(tx_data, 4);

    /* 写入图像数据 */
    lcd_send_cmd(0x2C);
    lcd_send_color(pix_data, (x1-x0+1)*(y1-y0+1));
}

void bsp_lcd_draw_rect_wait()
{
    while(dma_trans_done_flag == 0); //等待传输完毕
    dma_trans_done_flag = 0;    
    while(spi_i2s_flag_get(LCD_SPI_PR, SPI_I2S_BF_FLAG) == SET); //DMA传输完成中断产生时，SPI的最后一个字节仍在传输中，不能提前释放CS
    LCD_CS_On(); //CS=1
}

void bsp_lcd_display_switch(uint8_t status)
{
    if(status) {
        lcd_send_cmd(0x29); //开显示
    } else {
        lcd_send_cmd(0x28); //关显示
    }
}

void bsp_lcd_init()
{
    lcd_bus_init();
    lcd_reg_init_st7789v();
}
